/**
 * 项目名：化工企业安全生产信息化管理平台
 * 日期：    2020-07-26 17:45:28
 * Copyright (c) 2015- -版权所有
 */

package com.joysuch.wwyt.bp.service.impl;

import cn.zlg.common.util.CollectionUtils;
import com.joysuch.wwyt.bp.bean.BpDeviceFacilityMaintainRecordDetailBean;
import com.joysuch.wwyt.bp.bean.BpDeviceFacilityMaintainRecordEditBean;
import com.joysuch.wwyt.bp.bean.BpDeviceFacilityMaintainRecordListBean;
import com.joysuch.wwyt.bp.bean.BpDeviceFacilityMaintainRecordListBean.SearchBpDeviceFacilityMaintainRecord;
import com.joysuch.wwyt.bp.bean.facility.BpProductionFacilityTypeDto;
import com.joysuch.wwyt.bp.entity.BpDeviceFacilityMaintainRecord;
import com.joysuch.wwyt.bp.entity.BpProductionFacility;
import com.joysuch.wwyt.bp.entity.dsl.QBpDeviceFacilityMaintainRecord;
import com.joysuch.wwyt.bp.enums.DeviceFacilityMaintainStates;
import com.joysuch.wwyt.bp.enums.DeviceFacilityRepairStates;
import com.joysuch.wwyt.bp.repository.BpDepartDao;
import com.joysuch.wwyt.bp.repository.BpDeviceFacilityMaintainRecordDao;
import com.joysuch.wwyt.bp.repository.BpProductionFacilityDao;
import com.joysuch.wwyt.bp.service.BpDeviceFacilityMaintainRecordService;
import com.joysuch.wwyt.bp.service.BpProductionFacilityService;
import com.joysuch.wwyt.bp.service.BpProductionFacilityTypeService;
import com.joysuch.wwyt.common.entity.CommonIndexNotify;
import com.joysuch.wwyt.common.enums.CommonIndexNotifyTypes;
import com.joysuch.wwyt.common.service.CommonIndexNotifyService;
import com.joysuch.wwyt.core.common.util.DateTimeUtil;
import com.joysuch.wwyt.core.common.util.PageDataUtils;
import com.joysuch.wwyt.core.common.util.PageDataUtils.PageDataConvert;
import com.joysuch.wwyt.core.enums.Status;
import com.joysuch.wwyt.core.exception.ApiBusinessException;
import com.joysuch.wwyt.core.exception.BusinessRestrictionsException;
import com.joysuch.wwyt.core.repository.BaseUserDao;
import com.joysuch.wwyt.core.service.BaseAttachmentRepositoryService;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Predicate;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;

@Service
@Transactional(rollbackFor = Exception.class)
public class BpDeviceFacilityMaintainRecordServiceImpl implements BpDeviceFacilityMaintainRecordService {

    @Autowired
    private BpDeviceFacilityMaintainRecordDao dao;
    @Autowired
    private BaseUserDao baseUserDao;
    @Autowired
    private BpDepartDao bpDepartDao;
    @Autowired
    private BaseAttachmentRepositoryService baseAttachmentRepositoryService;
    @Autowired
    private BpProductionFacilityDao facilityDao;
    @Autowired
    private BpProductionFacilityService facilityService;
    @Autowired
    private BpProductionFacilityTypeService bpProductionFacilityTypeService;
    @Autowired
    private CommonIndexNotifyService commonIndexNotifyService;

    @Override
    public BpDeviceFacilityMaintainRecord add(BpDeviceFacilityMaintainRecordEditBean entity) throws ApiBusinessException {
        BpDeviceFacilityMaintainRecord content = new BpDeviceFacilityMaintainRecord();
        BeanUtils.copyProperties(entity, content, "id");
        if (entity.getAttachment() != null) {
            content.setAttachmentId(entity.getAttachment().getId());
        }
        if (entity.getMaintenanceAmount() == null) {
            entity.setMaintenanceAmount(0.0);
            content.setMaintenanceAmount(0.0);
        }
        BpDeviceFacilityMaintainRecord save = dao.save(content);
        //保养后重新计算
        //原本必须要有到期时间，并且保养周期需要>0，才会触发通知时间的重计算
        Long facilityId = entity.getDeviceFacilityId();
        BpProductionFacility facility = facilityDao.getOne(facilityId);
        //更改设备保养状态
        this.saveDeviceMaintainState(facilityId);
//        Date validityDate = facility.getValidityDate();
        Date maintainEndDate = entity.getMaintainEndDate();
        Integer maintainPeriodDays = facility.getMaintainPeriodDays();
        //保养金额
        if (facility.getMaintenanceAmount() == null) {
            facility.setMaintenanceAmount(entity.getMaintenanceAmount());
        } else {
            facility.setMaintenanceAmount(facility.getMaintenanceAmount() + entity.getMaintenanceAmount());
        }

        if (maintainEndDate != null && maintainPeriodDays != null && maintainPeriodDays > 0 && facility.getType() != null) {
            BpProductionFacilityTypeDto dto = bpProductionFacilityTypeService.getById(facility.getType());
            LocalDateTime newTime = DateTimeUtil.date2LocalDateTime(maintainEndDate).plusDays(maintainPeriodDays);
            if (StringUtils.isBlank(dto.getRemindType())) {
                throw new ApiBusinessException(Status.REMIND_TYPE_NOT_FIND_ERROR);
            }
            LocalDateTime notifyTime = newTime.minusDays(Integer.parseInt(dto.getRemindType()));
            Date date = DateTimeUtil.localDateTime2Date(newTime);
            Date notifyDate = DateTimeUtil.localDateTime2Date(notifyTime);
            //如果此次填写的信息需要未来或者今天提醒，并且此记录不是最新的记录则无需新增到期提醒记录
            if (!notifyDate.before(new Date()) && !isLastRecord(save)){
                facilityDao.save(facility);
                return content;
            }
            //如果是提醒未来的消息并且是最新的记录则去除未来还未发出的通知
            if (notifyDate.after(new Date())){
                facilityService.removeRemindNotify(facilityId, CommonIndexNotifyTypes.PRODUCTION_FACILITY.getType());
            }
            if (facility.getType() != null) {
                facilityService.remindNotify(facility.getName(), facilityId, save.getId(), facility.getType(), notifyDate, date, CommonIndexNotifyTypes.PRODUCTION_FACILITY.getType(), "设备保养");
            }
//            facility.setValidityDate(date);
            facilityDao.save(facility);
        }
        return content;
    }

    private void saveDeviceMaintainState(Long facilityId) {
        BpProductionFacility facility = facilityDao.findById(facilityId).orElseThrow(() -> new IllegalArgumentException("设备设施不存在"));
        int count = dao.countByDeviceFacilityIdAndNowDate(facilityId, new Date());
        if (count > 0) {
            facility.setRepairState(DeviceFacilityRepairStates.REPAIRING.getId());
        } else {
            facility.setRepairState(DeviceFacilityRepairStates.OK.getId());
        }
        facilityDao.save(facility);
    }

    @Override
    public void update(BpDeviceFacilityMaintainRecordEditBean entity) {
        BpDeviceFacilityMaintainRecord content = dao.findById(entity.getId()).get();
        BeanUtils.copyProperties(entity, content, "id");
        if (entity.getAttachment() != null) {
            content.setAttachmentId(entity.getAttachment().getId());
        } else {
            content.setAttachmentId(null);
        }
        dao.save(content);
        //更改设备保养状态
        this.saveDeviceMaintainState(entity.getDeviceFacilityId());
    }

    /**
     * 此生产装置是否有保养记录
     */
    @Override
    public boolean hasMaintainRecord(Long deviceFacilityId) {
        int count = dao.countByDeviceFacilityId(deviceFacilityId);
        return count > 0;
    }

    /**
     * 删除
     *
     * @param recordId
     */
    @Override
    public void deleteById(Long recordId) {
        BpDeviceFacilityMaintainRecord maintainRecord = dao.findById(recordId).orElseThrow(() -> new IllegalArgumentException("保养记录不存在"));
        dao.deleteById(recordId);
        //该条记录所绑定的到期提醒也要删掉
        List<CommonIndexNotify> list = commonIndexNotifyService.getByTypeAndRecordId(CommonIndexNotifyTypes.PRODUCTION_FACILITY.getType(), recordId);
        if (CollectionUtils.isNotEmpty(list)) {
            for (CommonIndexNotify notify : list) {
                if (notify != null && notify.getRemindedOrNot() == 0) {
                    commonIndexNotifyService.cancelAndRemove(notify);
                    commonIndexNotifyService.delete(notify.getId());
                }
            }
        }
        //更改设备保养状态
        this.saveDeviceMaintainState(maintainRecord.getDeviceFacilityId());
    }


    @Override
    public Page<BpDeviceFacilityMaintainRecordListBean> findByPage(Pageable page,
                                                                   SearchBpDeviceFacilityMaintainRecord condition) {
        Predicate predicate = prepareListSearchCondition(condition);

        Page<BpDeviceFacilityMaintainRecord> data = predicate == null ? dao.findAll(page)
                : dao.findAll(predicate, page);

        return PageDataUtils.convertPageData(data,
                new PageDataConvert<BpDeviceFacilityMaintainRecordListBean, BpDeviceFacilityMaintainRecord>() {

                    @Override
                    public BpDeviceFacilityMaintainRecordListBean convert(BpDeviceFacilityMaintainRecord f) {
                        BpDeviceFacilityMaintainRecordListBean bean = new BpDeviceFacilityMaintainRecordListBean();
                        BeanUtils.copyProperties(f, bean);
                        bean.setMaintainDepartName(bpDepartDao.getNameById(f.getMaintainDepartId()));
                        bean.setMaintainPersonName(baseUserDao.getBaseUserNameById(f.getMaintainPersonId()));
                        bean.setRegisterUserName(baseUserDao.getBaseUserNameById(f.getRegisterUserId()));
                        if (f.getMaintenanceAmount() == null) {
                            bean.setMaintenanceAmount(0 + ".00");
                        } else {
                            String s = String.format("%.2f", f.getMaintenanceAmount());
                            bean.setMaintenanceAmount(s);
                        }
                        return bean;
                    }

                });
    }

    private Predicate prepareListSearchCondition(SearchBpDeviceFacilityMaintainRecord condition) {
        Predicate p = null;
        QBpDeviceFacilityMaintainRecord q = QBpDeviceFacilityMaintainRecord.bpDeviceFacilityMaintainRecord;
        if (condition.getRegisterTime() != null) {
            p = ExpressionUtils.and(p, q.registerTime.eq(condition.getRegisterTime()));
        }
        if (condition.getMaintainDate() != null) {
            p = ExpressionUtils.and(p, q.maintainDate.eq(condition.getMaintainDate()));
        }
        if (condition.getMaintainPersonId() != null) {
            p = ExpressionUtils.and(p, q.maintainPersonId.eq(condition.getMaintainPersonId()));
        }
        if (condition.getMaintainDepartId() != null) {
            p = ExpressionUtils.and(p, q.maintainDepartId.eq(condition.getMaintainDepartId()));
        }
        if (condition.getRegisterUserId() != null) {
            p = ExpressionUtils.and(p, q.registerUserId.eq(condition.getRegisterUserId()));
        }
        if (condition.getAttachmentId() != null) {
            p = ExpressionUtils.and(p, q.attachmentId.eq(condition.getAttachmentId()));
        }
        if (condition.getMaintainStatus() != null) {
            p = ExpressionUtils.and(p, q.maintainStatus.eq(condition.getMaintainStatus()));
        }
        if (condition.getDeviceFacilityId() != null) {
            p = ExpressionUtils.and(p, q.deviceFacilityId.eq(condition.getDeviceFacilityId()));
        }
        return p;
    }

    @Override
    public void delete(Long id) throws BusinessRestrictionsException {
        // 校验业务逻辑是否允许删除。如本数据被其他业务关联，删除后导致其他业务不可用。不能删除时将抛出业务异常
        checkBussinessRestrictions(id);
        dao.deleteById(id);
    }

    /**
     * 校验业务逻辑是否允许删除。如本数据被其他业务关联，删除后导致其他业务不可用
     *
     * @param id 要删除的业务ID
     * @throws BusinessRestrictionsException 抛出的业务异常
     */
    private void checkBussinessRestrictions(Long id) throws BusinessRestrictionsException {
    }

    @Override
    public BpDeviceFacilityMaintainRecord findById(Long id) {
        return dao.findById(id).orElse(null);
    }

    @Override
    public BpDeviceFacilityMaintainRecordDetailBean getById(Long id) {
        BpDeviceFacilityMaintainRecord entity = findById(id);
        if (entity == null) {
            return null;
        }
        BpDeviceFacilityMaintainRecordDetailBean bean = new BpDeviceFacilityMaintainRecordDetailBean();
        BeanUtils.copyProperties(entity, bean);
        if (entity.getAttachmentId() != null) {
            bean.setAttachment(baseAttachmentRepositoryService.findByIdIntoBean(entity.getAttachmentId()));
        }
        if (entity.getMaintainDepartId() != null) {
            bean.setMaintainDepartName(bpDepartDao.findDepartNameById(entity.getMaintainDepartId()));
        }
        if (entity.getMaintainPersonId() != null) {
            bean.setMaintainPersonName(baseUserDao.getBaseUserNameById(entity.getMaintainPersonId()));
        }
        if (entity.getRegisterUserId() != null) {
            bean.setRegisterUserName(baseUserDao.getBaseUserNameById(entity.getRegisterUserId()));
        }
        bean.setMaintenanceAmount(entity.getMaintenanceAmount());
        return bean;
    }

    /**
     * 查看是否是最新的记录
     * @param save
     * @return
     */
    private boolean isLastRecord(BpDeviceFacilityMaintainRecord save){
        Long id = save.getId();
        Long deviceFacilityId = save.getDeviceFacilityId();
        Date maintainEndDate = save.getMaintainEndDate();
        Long lastRecord =  dao.isLastRecord(id,deviceFacilityId,maintainEndDate);
        return lastRecord == 0;
    }
}
